/* 
 * File:   banco.cpp
 * Author: ednei
 * 
 * Created on 13 de Abril de 2014, 18:34
 */


#include "banco.h"

/*
 * Construtor que conecta ao banco de dados
 */
banco::banco(const char* file) {
    this->status = true;

    /* realiza conexão com o banco de dados */
    if (sqlite3_open(file, &this->db) != SQLITE_OK) {
        this->status = false;
        this->msg_db = "Erro ao conectar ao banco de dados, verifique se o banco de dados '";
        this->msg_db.append(file);
        this->msg_db += "' existe e tente novamente";
    }

    /* habilita a verificação de chaves estrangeiras */
    this->query("PRAGMA foreign_keys = ON;");
    
    /* habilita vacuum automatico */
    this->query("PRAGMA auto_vacuum = FULL;");
}

/*
 * Destrutor que encerra conexão com banco
 */
banco::~banco() {
    sqlite3_close(this->db);
}

/*
 * Método que inicializa transaction
 */
void banco::begin() {
    this->query("BEGIN;");
}

/*
 * Método que finaliza transaction
 */
void banco::commit() {
    this->query("COMMIT;");
}

/*
 * Método que cancela operação realizadas anteriormente
 */
void banco::rollback() {
    this->query("ROLLBACK;");
}

/*
 * Método que realiza diversas operações no banco de dados
 */
bool banco::query(const char *sql) {
    int cont, result;
    sqlite3_stmt *statement;
    vector<string> valores;
    char *value;

    /*
     * realiza a execução da query
     * e o instanciamento da variavel statement
     */
    if (sqlite3_prepare_v2(this->db, sql, -1, &statement, 0) != SQLITE_OK) {
        this->status = false;
        return this->status;
    }

    /* caso a consulta seja um select o valor sera diferente de zero */
    if (sqlite3_column_count(statement)) {

        /* realiza tratamento de exceções de alocação de mémoria */
        try {
            this->colunas = sqlite3_column_count(statement);
            this->resultados.clear();
            this->registros = 0;

            while (true) {
                result = sqlite3_step(statement);
                if (result == SQLITE_ROW) {
                    valores.clear();
                    for (cont = 0; cont < this->colunas; cont++) {
                        value = (char*) sqlite3_column_text(statement, cont);
                        valores.push_back((value ? value : ""));
                    }
                    this->resultados.push_back(valores);
                    this->registros++;
                } else {
                    break;
                }
            }
        } catch (std::bad_alloc &falha) {

            /* tratamentos de possiveis exceções caso ocorra */
            cout << falha.what() << ": banco" << endl;
            sqlite3_finalize(statement);
            this->status = false;
            return false;
        }

        /*
         * Caso a consulta não retorne nenhum valor status
         * da operação é considerada false
         */
        this->status = (this->registros == 0 ? false : true);
    } else if (sqlite3_step(statement) == SQLITE_DONE) {
        /*
         * Caso seja uma operação de insert, update e delete
         * as linha abaixo são executadas
         */
        this->status = true;
    } else {
        this->status = false;
        this->msg_db.clear();
        this->msg_db = "Erro ao executar operação.";
    }

    /* finaliza instancimento */
    sqlite3_finalize(statement);
    return this->status;
}

/*
 * retorna status da conexão. Retorna false quando ocorre erro
 */
bool banco::getStatus(void) {
    return this->status;
}

/*
 * Método que retorna mensagem de erros
 */
string banco::getMsgDB(void) {
    return this->msg_db;
}

